/* 
 * Copyright [2018] [Alex/libo(liboms@hotmail.com)]
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hyts.guava.hash;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import com.google.common.base.Charsets;
import com.google.common.hash.Funnel;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import com.google.common.hash.PrimitiveSink;

/** 
 * @title Hashs.java  
 * @package com.hyts.guava.hash  
 * @description Java 内建的散列码[hash code]概念被限制为 32 位，并且没有分离散列算法和它们所作用的数据，因此很难用<br>
				  备选算法进行替换。此外，使用 Java 内建方法实现的散列码通常是劣质的，部分是因为它们最终都依赖于 JDK<br>
				  类中已有的劣质散列码。<br>
				 Object.hashCode 往往很快，但是在预防碰撞上却很弱，也没有对分散性的预期。这使得它们很适合在散列表<br>
				  中运用，因为额外碰撞只会带来轻微的性能损失，同时差劲的分散性也可以容易地通过再散列来纠正（Java 中所<br>
				 有合理的散列表都用了再散列方法）。然而，在简单散列表以外的散列运用中，Object.hashCode 几乎总是达<br>
				 不到要求——因此，有了 com.google.common.hash 包。<br>  
 * @see TODO
 * @author libo/Alex
 * @email liboms@hotmail.com/liboware@163.com  
 * @date 2018年5月28日 
 * @version V1.0 
 */
public final class Hashs {

	
	public Hashs(){
		this.hasher = new ExtGuavaHash().getHashType(hashType.MD5);
					 }

	public Hashs(hashType type){
		this.hasher = new ExtGuavaHash().getHashType(type);
					 }
	/**
	 * @fieldName: hasher
	 * @fieldType: Hasher
	 * @Description: Hash生成器
	 */
	private Hasher hasher ;
	
	/**
	 * @ClassName: hashType
	 * @Description: Hash编码类型
	 * @author: libo
	 * @date: 2017年1月11日 下午2:15:06
	 */
	public enum hashType{
		SHA1,
		CRC32,
		MD5,
		SHA256,
		SHA512,
		SIPHASH,
		ADLER,
		MURMUR;
	}
	
	private final class ExtGuavaHash {

		
		/**
		 * @Title: getHashType
		 * @Description: 获取Hash编码的类型操作
		 * @return
		 * @return: Integer
		 */
		public Hasher getHashType(hashType hashType){
			/*Random random = new Random();
			int randomType = random.nextInt(10);*/
			HashFunction function = null;
			switch(hashType){
				case SHA1: function = Hashing.sha1();break;
				case CRC32: function = Hashing.crc32();break;
				case MD5: function = Hashing.md5();break;
				case SHA256: function = Hashing.sha256();break;
				case SHA512: function = Hashing.sha512();break;
				case SIPHASH: function = Hashing.sipHash24();break;
				case ADLER: function = Hashing.adler32();break;
				case MURMUR: function = Hashing.murmur3_128();break;
				default: function = Hashing.md5();
			}
			return function.newHasher();
	  }
	}
		
	  /**
	   * @ClassName: ExtFunnel
	   * @Description: 扩展Funnel利用反射方法进行
	   * @author: libo
	   * @date: 2017年1月11日 下午2:29:05
	   */
		@SuppressWarnings("serial")
		public class ExtFunnel<T> implements Funnel<T>{
			
			private T t;
			
			public ExtFunnel(T t){this.t = t;}
			
			public ExtFunnel(){}
			
			public T getT() {
				return t;
			}

			public void setT(T t) {
				this.t = t;
			}

			@Override
			public void funnel(T from, PrimitiveSink into) {
				from = this.t;
				if(from == null)
					throw new RuntimeException("传入的对象数值为空!");
				Map<String,Object> paramMap = _analysisClassArtic(from);
				for(Entry<String,Object> element: paramMap.entrySet()){
					Object obj = element.getValue();
					//匹配对应的数据类型
					if(obj instanceof Long){
						into.putLong(((Long) obj).longValue());
					}else if(obj instanceof Integer){
						into.putInt(((Integer) obj).intValue());
					}else if(obj instanceof Short){
						into.putShort(((Short) obj).shortValue());
					}else if(obj instanceof Byte){
						into.putByte(((Byte) obj).byteValue());
					}else if(obj instanceof String || obj instanceof CharSequence){
						into.putString((CharSequence)obj,Charsets.UTF_8);
					}else if(obj instanceof Byte[]){
						 into.putBytes((byte[])obj);
					}else if(obj instanceof Float){
						 into.putFloat((Float)obj);
					}else if(obj instanceof Double){
						 into.putDouble((Double)obj);
					}else if(obj instanceof Boolean){
						 into.putBoolean((Boolean)obj);
					}else if(obj instanceof Character){
						 into.putChar((Character)obj);
					}
				}
			}
		}	
		
		/********************************针对于Guava框架的Object是对象工具的-toStringHelper方法的封装以及额外支持*****************************************************/
		
		/**
		 * @Title: analysisClassArtic
		 * @Description: 分析ClassName名称对的ClassName对应的数据Class结构信息<br>
		 * 				   此处采用的是ClassLoader的方法操作 并非对应的Class方法 静态方法不进行初始化
		 * @param clazzName
		 * @return: String[]
		 */
		public String[] _analysisClassArtic(String clazzName){
			if(clazzName == null || clazzName.trim().length() == 0)
				throw new RuntimeException("传入的ClassName名称为空!");
			Class<?> clazz = null;
			try {
				clazz = Hashs.class.getClassLoader().loadClass(clazzName);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
			return _accessClassArtic0(clazz);
		}
		
		/**
		 * @Title: analysisClassArtic
		 * @Description: 分析ClassName名称对的ClassName对应的数据Class结构信息<br>
		 * 				   此处采用的是ClassLoader的方法操作 并非对应的Class方法 静态方法不进行初始化
		 * @param clazz
		 * @return: String[]
		 */
		public String[] _analysisClassArtic(Class<?> clazz){
			if(clazz == null)
				throw new RuntimeException("传入的Class类型对象为空!");
			return _accessClassArtic0(clazz);
		}
		
		/**
		 * @Title: analysisClassArtic
		 * @Description: 分析ClassName名称对的ClassName对应的数据Class结构信息<br>
		 * 				   此处采用的是ClassLoader的方法操作 并非对应的Class方法 静态方法不进行初始化
		 * @param instance
		 * @return: Map<String,Object>
		 */
		public Map<String,Object> _analysisClassArtic(Object instance){
			if(instance == null)
				throw new RuntimeException("传入的instance对象为空!");
			try {
				return _accessClassArtic1(instance);
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return null;
		}
		
		/**
		 * @Title: accessClassArtic
		 * @Description: 访问对应的ClassArtic对象结构数据操作<br>
		 * 				   此方法为共有方法 所有如果需要修改需要格外慎重<br>
		 * 				   此方法采用的是get方法进行访问操作 如果Pojo类没有<br>
		 * 				  没有进行get方法是拿不到对应的数据信息
		 * @param clazz
		 * @return
		 * @return: Map<String,Object>
		 */
		
		private String[] _accessClassArtic0(Class<?> clazz){
			if(clazz == null)
				throw new RuntimeException("传入的Class类型对象为空!");
			Field[] fields = clazz.getDeclaredFields();
			if(fields == null || fields.length == 0)
				return null;
			String[] clazzArtiArray = new String[fields.length];
			int count = 0;
			for(Field field:fields)
				clazzArtiArray[count++] = field.getName();
			return clazzArtiArray;
		}
		
		/**
		 * @Title: accessClassArtic
		 * @Description: 访问对应的ClassArtic对象结构数据操作<br>
		 * 				   此方法为共有方法 所有如果需要修改需要格外慎重<br>
		 * 				   此方法采用的是属性直接方法进行访问操作 如果Pojo类没有<br>
		 * 				  
		 * @param clazz
		 * @return
		 * @return: Map<String,Object>
		 * @throws InvocationTargetException 
		 * @throws IllegalArgumentException 
		 * @throws IllegalAccessException 
		 */
		private Map<String,Object> _accessClassArtic1(Object instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
			/*if(clazz == null)
				throw new RuntimeException("传入的Class类型对象为空!");*/
			Class<?> clazz = instance.getClass();
			Field[] fields = clazz.getDeclaredFields();
			if(fields == null || fields.length == 0)
				return null;
			Map<String,Object> clazzArtiMap = new HashMap<String,Object>();
			Method[] methods = clazz.getDeclaredMethods();
			for(Field field:fields){
				String fieldName = field.getName();
				Object fieldValue = null;
				if(field.isAccessible())
					fieldValue = field.get(instance);
				else{
					field.setAccessible(true);
					fieldValue =  field.get(instance);
				}
				clazzArtiMap.put(fieldName, fieldValue);
			}
			return clazzArtiMap;
		}
		/****************************进行散列方法的构建以及生产处理****************************************/
		
		/**
		 * @Title: getHashCode2Integer
		 * @Description: 获取整数类型的HashCode值
		 * @param obj
		 * @return
		 * @return: Integer
		 */
		public synchronized <T>Integer getHashCode2Integer(T obj){
			//hash算法执行器
			Hasher hasher = this.hasher ;
			//匹配对应的数据类型
			if(obj instanceof Long){
				return hasher.putLong(((Long) obj).longValue()).hash().asInt();
			}else if(obj instanceof Integer){
				return hasher.putInt(((Integer) obj).intValue()).hash().asInt();
			}else if(obj instanceof Short){
				return hasher.putShort(((Short) obj).shortValue()).hash().asInt();
			}else if(obj instanceof Byte){
				return hasher.putByte(((Byte) obj).byteValue()).hash().asInt();
			}else if(obj instanceof String || obj instanceof CharSequence){
				return hasher.putString((CharSequence)obj,Charsets.UTF_8).hash().asInt();
			}else if(obj instanceof Byte[]){
				return hasher.putBytes((byte[])obj).hash().asInt();
			}else if(obj instanceof Float){
				return hasher.putFloat((Float)obj).hash().asInt();
			}else if(obj instanceof Double){
				return hasher.putDouble((Double)obj).hash().asInt();
			}else if(obj instanceof Boolean){
				return hasher.putBoolean((Boolean)obj).hash().asInt();
			}else if(obj instanceof Character){
				return hasher.putChar((Character)obj).hash().asInt();
			}else{
				return hasher.putObject(obj, new ExtFunnel(obj)).hash().asInt();
			}
		}
		
		/**
		 * @Title: getHashCode2Long
		 * @Description: 获取长整数类型的HashCode值
		 * @param obj
		 * @return
		 * @return: long
		 */
		public synchronized <T>Long getHashCode2Long(T obj){
			//hash算法执行器
			Hasher hasher = this.hasher;
			//匹配对应的数据类型
			if(obj instanceof Long){
				return hasher.putLong(((Long) obj).longValue()).hash().asLong();
			}else if(obj instanceof Integer){
				return hasher.putInt(((Integer) obj).intValue()).hash().asLong();
			}else if(obj instanceof Short){
				return hasher.putShort(((Short) obj).shortValue()).hash().asLong();				
			}else if(obj instanceof Byte){
				return hasher.putByte(((Byte) obj).byteValue()).hash().asLong();
			}else if(obj instanceof String || obj instanceof CharSequence){
					return hasher.putString((CharSequence)obj,Charsets.UTF_8).hash().asLong();
			}else if(obj instanceof Byte[]){
					return hasher.putBytes((byte[])obj).hash().asLong();
			}else if(obj instanceof Float){
					return hasher.putFloat((Float)obj).hash().asLong();
			}else if(obj instanceof Double){
					return hasher.putDouble((Double)obj).hash().asLong();
			}else if(obj instanceof Boolean){
					return hasher.putBoolean((Boolean)obj).hash().asLong();
			}else if(obj instanceof Character){
					return hasher.putChar((Character)obj).hash().asLong();
			}else{
				return hasher.putObject(obj, new ExtFunnel(obj)).hash().asLong();
			}
		}
		
		/**
		 * @Title: getHashCode2Bytes
		 * @Description: 获取字节型数组类型的HashCode值
		 * @param obj
		 * @return
		 * @return: Long
		 */
		@SuppressWarnings("rawtypes")
		public synchronized <T>byte[] getHashCode2Bytes(T obj){
			//hash算法执行器
			Hasher hasher = this.hasher;
			//匹配对应的数据类型
			if(obj instanceof Long){
				return hasher.putLong(((Long) obj).longValue()).hash().asBytes();
			}else if(obj instanceof Integer){
				return hasher.putInt(((Integer) obj).intValue()).hash().asBytes();
			}else if(obj instanceof Short){
				return hasher.putShort(((Short) obj).shortValue()).hash().asBytes();
			}else if(obj instanceof Byte){
				return hasher.putByte(((Byte) obj).byteValue()).hash().asBytes();
			}else if(obj instanceof String || obj instanceof CharSequence){
				return hasher.putString((CharSequence)obj,Charsets.UTF_8).hash().asBytes();
			}else if(obj instanceof Byte[]){
				return hasher.putBytes((byte[])obj).hash().asBytes();
			}else if(obj instanceof Float){
				return hasher.putFloat((Float)obj).hash().asBytes();
			}else if(obj instanceof Double){
				return hasher.putDouble((Double)obj).hash().asBytes();
			}else if(obj instanceof Boolean){
				return hasher.putBoolean((Boolean)obj).hash().asBytes();
			}else if(obj instanceof Character){
				return hasher.putChar((Character)obj).hash().asBytes();
			}else{
				return hasher.putObject(obj, new ExtFunnel(obj)).hash().asBytes();
			}
		}
		
		/****************************布鲁姆过滤器[BloomFilter]****************************************/
		
		/**
		 * 布鲁姆过滤器[BloomFilter]<br>
		       布鲁姆过滤器是哈希运算的一项优雅运用，它可以简单地基于 Object.hashCode()实现。简而言之，布鲁姆过滤<br>
		       器是一种概率数据结构，它允许你检测某个对象是一定不在过滤器中，还是可能已经添加到过滤器了。布鲁姆过<br>
		      滤器的维基页面对此作了全面的介绍，同时我们推荐 github 中的一个教程。<br>
		  Guava 散列包有一个内建的布鲁姆过滤器实现，你只要提供 Funnel 就可以使用它。你可以使用 create(Funnel<br>
		  funnel, int expectedInsertions, double falsePositiveProbability)方法获取 BloomFilter，缺省误检率[falseP<br>
		  ositiveProbability]为 3%。BloomFilter 提供了 boolean mightContain(T) 和 void put(T)，它们的含义都不言<br>
		      自明了。
		 * 
		 */
		
		/****************************HashCode 运算****************************************/

		/**
		 * 方法 描述
			HashCode combineOrdered( It
			erable<HashCode>)
			以有序方式联接散列码，如果两个散列集合用该方法联接出的散列码相
			同，那么散列集合的元素可能是顺序相等的
			HashCode combineUnordered(
			Iterable<HashCode>)
			以无序方式联接散列码，如果两个散列集合用该方法联接出的散列码相
			同，那么散列集合的元素可能在某种排序下是相等的
			int consistentHash( HashCod
			e, int buckets)
			为给定的”桶”大小返回一致性哈希值。当”桶”增长时，该方法保证
			最小程度的一致性哈希值变化。详见一致性哈希。
		 */
		
	
}
